unit main;
(*
File Case Converter
Copyright (C) 2002-2012 Matthew Hipkin <http://www.matthewhipkin.co.uk>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*)
{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  EditBtn, Buttons, ExtCtrls, XiPanel, XiButton, httpsend, LCLIntF;

(*
  Makes use of Ararat Synapse http://www.ararat.cz/synapse/doku.php/start
  And XiControls http://www.matthewhipkin.co.uk/codelib/xicontrols/
*)

type

  { TfrmMain }

  TfrmMain = class(TForm)
    labelUpdate: TLabel;
    listOutput: TListBox;
    listFiles: TListBox;
    btnAddFile: TSpeedButton;
    btnDeleteFile: TSpeedButton;
    OpenDialog1: TOpenDialog;
    btnAbout: TSpeedButton;
    textDir: TDirectoryEdit;
    checkDir: TRadioButton;
    checkFiles: TRadioButton;
    updatesTimer: TTimer;
    toggleCase: TToggleBox;
    procedure btnAboutClick(Sender: TObject);
    procedure btnAddFileClick(Sender: TObject);
    procedure btnDeleteFileClick(Sender: TObject);
    procedure checkDirChange(Sender: TObject);
    procedure checkFilesChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure labelUpdateClick(Sender: TObject);
    procedure toggleCaseChange(Sender: TObject);
    procedure updatesTimerTimer(Sender: TObject);
  private
    { private declarations }
    bgPanel: TXiPanel;
    btnGo: TXiButton;
    updatePanel: TXiPanel;
    procedure btnGoClick(Sender: TObject);
  public
    { public declarations }
  end;

var
  frmMain: TfrmMain;

const
  APPNAME = 'File Case Converter';
  APPVER = '2.0';
  CURRVER = 20120905;
  {$ifdef Windows}
    OS = 'Windows';
  {$endif}
  {$ifdef Linux}
    OS = 'Linux';
  {$endif}
  {$ifdef FreeBSD}
    OS = 'FreeBSD';
  {$endif}
  {$ifdef Darwin}
    OS = 'Mac OSX';
  {$endif}

implementation

{$R *.lfm}

uses about;

function httpGet(URL: String): String;
var
  HTTP: THTTPSend;
  l: TStrings;
begin
  Result := '';
  l := TStringList.Create;
  HTTP := THTTPSend.Create;
  HTTP.UserAgent := 'Mozilla/5.0 (compatible; '+OS+'; File Case Converter '+APPVER+' ('+IntToStr(CURRVER)+'))';
  if HTTP.HTTPMethod('GET', URL) then
  begin
    l.LoadFromStream(Http.Document);
    Result := l.Text;
  end;
  HTTP.Free;
  l.Free;
end;

{ TfrmMain }

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  // Set up Application and Form title
  Application.Title := APPNAME;
  frmMain.Caption := APPNAME + ' ' + APPVER;
  // Create XiPanel and set child controls
  bgPanel := TXiPanel.Create(Self);
  bgPanel.Parent := frmMain;
  bgPanel.Align := alClient;
  bgPanel.BorderStyle := bsNone;
  bgPanel.BevelInner:=bvNone;
  bgPanel.BevelOuter := bvNone;
  bgPanel.ColorScheme := XiPanel.csSky;
  checkDir.Parent := bgPanel;
  checkFiles.Parent := bgPanel;
  textDir.Parent := bgPanel;
  listFiles.Parent := bgPanel;
  btnAddFile.Parent := bgPanel;
  btnDeleteFile.Parent := bgPanel;
  listOutput.Parent := bgPanel;
  toggleCase.Parent := bgPanel;
  toggleCase.Checked := false;
  toggleCase.Caption := 'Lowercase';
  btnAbout.Parent := bgPanel;
  btnGo := TXiButton.Create(Self);
  btnGo.Parent := bgPanel;
  btnGo.Left := 188;
  btnGo.Top := 330;
  btnGo.Width := 75;
  btnGo.Height := 25;
  btnGo.Caption := 'Go';
  btnGo.ColorScheme := csNeoGrass;
  btnGo.OnClick := @btnGoClick;
  updatePanel := TXiPanel.Create(self);
  updatePanel.Parent := bgPanel;
  updatePanel.Height := 25;
  updatePanel.Top := frmMain.ClientHeight - (updatePanel.Height + 5);
  updatePanel.Width := frmMain.Width div 2;
  updatePanel.Left := (frmMain.ClientWidth div 2) - (updatePanel.Width div 2);
  updatePanel.ColorScheme := XiPanel.csRose;
  labelUpdate.Parent := upDatePanel;
  labelUpdate.Align := alClient;
  labelUpdate.Alignment := taCenter;
  labelUpdate.Layout := tlCenter;
  labelUpdate.Caption := 'A new version is available';
  updatePanel.Visible := false;
  updatesTimer.Enabled := true;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  bgPanel.Free;
  updatePanel.Free;
  btnGo.Free;
end;

procedure TfrmMain.FormResize(Sender: TObject);
begin
  { Anchors don't seem to like having an XiPanel as parent in Lazarus
    so this is the safe method }
  listOutput.Width := frmMain.ClientWidth - (listOutput.Left * 2);
  listOutput.Height := (frmMain.ClientHeight - listOutput.Top) - (btnGo.Height + 10);
  listFiles.Width := frmMain.ClientWidth - (listFiles.Left * 2);
  btnDeleteFile.Left := listFiles.Left + listFiles.Width;
  btnAddFile.Left := listFiles.Left + listFiles.Width;
  textDir.Width := frmMain.ClientWidth - (textDir.Left * 2);
  toggleCase.Top := frmMain.ClientHeight - (toggleCase.Height + 5);
  btnGo.Top := frmMain.ClientHeight - (btnGo.Height + 5);
  btnGo.Left := frmMain.ClientWidth - (btnGo.Width + 8);
  updatePanel.Top := frmMain.ClientHeight - (updatePanel.Height + 5);
  updatePanel.Left := (frmMain.ClientWidth div 2) - (updatePanel.Width div 2);
  btnAbout.Left := frmMain.ClientWidth - (btnAbout.Width + 8);
end;

procedure TfrmMain.labelUpdateClick(Sender: TObject);
begin
  OpenURL('http://www.matthewhipkin.co.uk');
end;

procedure TfrmMain.toggleCaseChange(Sender: TObject);
begin
  if toggleCase.Checked then toggleCase.Caption := 'Uppercase'
  else toggleCase.Caption := 'Lowercase';
end;

procedure TfrmMain.updatesTimerTimer(Sender: TObject);
var
  response: String;
  newVer: Boolean;
begin
  updatesTimer.Enabled := false;
  // Check for a new version comparing the CURRVER variable to the value returned
  newVer := false;
  try
    response := httpGet('http://www.matthewhipkin.co.uk/fccgui.txt');
    response := trim(response);
    if CURRVER < StrToInt(response) then newVer := true;
  except
    newVer := false;
  end;
  if newVer then
  begin
    updatePanel.Visible := true;
  end;
end;

procedure TfrmMain.checkDirChange(Sender: TObject);
begin
  if checkDir.Checked then
  begin
    textDir.Enabled := true;
    listFiles.Enabled := false;
    btnAddFile.Enabled := false;
    btnDeleteFile.Enabled := false;
  end;
end;

procedure TfrmMain.checkFilesChange(Sender: TObject);
begin
  if checkFiles.Checked then
  begin
    textDir.Enabled := false;
    listFiles.Enabled := true;
    btnAddFile.Enabled := true;
    btnDeleteFile.Enabled := true;
  end;
end;

procedure TfrmMain.btnAddFileClick(Sender: TObject);
begin
  // Execute open dialog, add any selected files to list
  if OpenDialog1.Execute then
  begin
    listFiles.Items.AddStrings(OpenDialog1.Files);
  end;
end;

procedure TfrmMain.btnAboutClick(Sender: TObject);
begin
  frmAbout.ShowModal;
end;

procedure TfrmMain.btnDeleteFileClick(Sender: TObject);
var
  x: integer;
begin
  // Remove any selected files from list
  for x := listFiles.Count-1 downto 0 do
    if listFiles.Selected[x] then listFiles.Items.Delete(x);
end;

procedure TfrmMain.btnGoClick(Sender: TObject);
var
  x: integer;
  path: String;
  newFilename: String;
  s: TSearchRec;
begin
  listOutput.Clear;
  // Renaming all files in a directory
  if checkDir.Checked then
  begin
    if not DirectoryExists(textDir.Text) then exit;
    if FindFirst(IncludeTrailingPathDelimiter(textDir.Text) + '*', faAnyFile, s) = 0 then
    begin
      repeat
        newFilename := '';
        // We're only interested in files, not directories
        if (s.Attr and not faDirectory) <> 0 then
        begin
          if toggleCase.Checked then
            newFileName := Uppercase(s.Name)
          else
            newFileName := Lowercase(s.Name);
          RenameFileUTF8(IncludeTrailingPathDelimiter(textDir.Text) + s.Name,IncludeTrailingPathDelimiter(textDir.Text) + newFilename);
          listOutput.Items.Add(IncludeTrailingPathDelimiter(textDir.Text) + s.Name + ' >> ' + IncludeTrailingPathDelimiter(textDir.Text) + newFilename);
        end;
      until FindNext(s) <> 0;
    end;
  end;
  // Renaming only selected files
  if checkFiles.Checked then
  begin
    for x := 0 to listFiles.Count -1 do
    begin
      if FileExists(listFiles.Items[x]) then
      begin
        path := ExtractFilePath(listFiles.Items[x]);
        if toggleCase.Checked then
          newFileName := Uppercase(ExtractFileName(listFiles.Items[x]))
        else
          newFileName := Lowercase(ExtractFileName(listFiles.Items[x]));
        RenameFileUTF8(listFiles.Items[x],path + newFilename);
        listOutput.Items.Add(listFiles.Items[x] + ' >> ' + path + newFilename);
      end;
    end;
  end;
  for x := 0 to listOutput.Items.Count -1 do
  begin
    if listOutput.Canvas.TextWidth(listOutput.Items[x]) > listOutput.ScrollWidth then listOutput.ScrollWidth := listOutput.Canvas.TextWidth(listOutput.Items[x]);
  end;
end;

end.

